package com.zm.shop.controller;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.zm.shop.common.constants.AuthCons;
import com.zm.shop.common.constants.RabbitMQCons;
import com.zm.shop.common.constants.RedisCons;
import com.zm.shop.common.entity.Email;
import com.zm.shop.common.entity.SmsEntity;
import com.zm.shop.common.entity.UserEntity;
import com.zm.shop.common.exception.BusinessException;
import com.zm.shop.common.utils.JWTUtils;
import com.zm.shop.common.utils.R;
import com.zm.shop.feign.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/auth")
@Slf4j
public class AuthController {

    @Autowired
    private UserService userService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @RequestMapping("/check")   //异步检测用户名和邮箱是否被注册
    public Map<String,Object> checkUsername(@RequestParam("name") String field,@RequestParam("param") String value){
        Map<String,Object> map=new HashMap<>();
        // 简单过滤一下（异步）输入的内容
        if (StringUtils.isEmpty(field)){ //没有传字段,返回字段为空
            map.put("status","n");
            map.put("info","字段名称为空");
            return map;
        }
        if (StringUtils.isEmpty(value)){ //没有传值,返回值为空
            map.put("status","n");
            map.put("info","用户名或邮箱为空");
            return map;
        }
        //查询用户名是否被注册（通过username或Email查询）
        UserEntity userEntity = userService.findUser(field, value);
        if (userEntity==null){  //用户名不存在
            map.put("status", "y");
            map.put("info", "用户名可以注册");
        }else if ("username".equals(field)){    //用户名存在 判断是用户名还是邮箱被注册
            map.put("status", "n");
            map.put("info", "用户名已被注册");
        }else if ("email".equals(field)){
            map.put("status", "n");
            map.put("info", "邮箱已被注册");
        }
        return map;
    }


    @RequestMapping("/sendPhoneCode/{phone}")  //发送手机验证码
    public void sendPhoneCode(@PathVariable String phone){
        //1 .如果手机号为空，抛一个异常
        if (StringUtils.isEmpty(phone)) {
            throw new BusinessException("手机号不能为空", 666);
        }
        // 2.生成验证码
        String code = RandomStringUtils.random(4, false, true);
        // 3.保存验证码到reids共享
        String key = RedisCons.AUTH_USER_REGISTER_PRE + phone;
        //保存验证码
        redisTemplate.opsForValue().set(key, code, 60, TimeUnit.SECONDS);
        // 4.发送短信(通过MQ发送sms消息)
        SmsEntity smsEntity = new SmsEntity();
        smsEntity.setPhone(phone);
        smsEntity.setCode(code);
        //发送消息给MQ
        rabbitTemplate.convertAndSend(RabbitMQCons.SENDSMS_EXCHANGE, "sms.send", smsEntity);
    }

    @RequestMapping("/register") //用户注册
    public R register(@RequestBody UserEntity userEntity){
        System.out.println("接收的注册信息是："+userEntity);

        //查询用户是否存在 防止重复注册
        UserEntity user = userService.findUser("username", userEntity.getUsername());
        if (user!=null){
            throw new BusinessException("用户名已存在", 502);
        }
        //1.获取表单验证码
        String code = userEntity.getCode();
        //2.手机验证码和redis里的验证码比对
        String key = RedisCons.AUTH_USER_REGISTER_PRE + userEntity.getPhone(); //设置.redis的key
        String redisCode = redisTemplate.opsForValue().get(key);               //获取redis的vaule
        if (StringUtils.isEmpty(redisCode)) { //为空-过期
            throw new BusinessException("验证码失效，请重新获取", 502);
        }
        if (!redisCode.equals(code)) {  //验证码不对
            throw new BusinessException("验证码输入有误", 502);
        }
        //3.密码加密
        userEntity.setPassword(BCrypt.hashpw(userEntity.getPassword(),BCrypt.gensalt()));
        //4.注册
        R r= userService.register(userEntity);
        System.out.println("注册结果是："+r);
        return R.ok();//注册成功
    }

    @RequestMapping("/login")  //用户登入
    public R login(@RequestBody UserEntity userEntity, HttpSession httpSession){
        //1.查询用户名
        UserEntity user = userService.findUser("username", userEntity.getUsername());
        if (user==null){
            throw new BusinessException("用户名不存在", 500);
        }

        try {
            //2.比较密码     输入的密码和数据库密码比较,数据库内的加密内容会进行解密
            boolean checkpw = BCrypt.checkpw(userEntity.getPassword(), user.getPassword());
        if (!checkpw) {
            throw new BusinessException("用户名或密码错误", 500);
        }
        } catch (Exception e) {
            log.error("用户密码比对失败", e);
            throw new BusinessException("用户名或密码错误", 500);
        }
        //比对成功 清空密码存入到session 通过SringSession存储到redis，用于解决单点验证
        user.setPassword(null);
        httpSession.setAttribute(AuthCons.LOGIN_USER,user);
        return R.ok();
    }

    @GetMapping("/logout") //注销登入
    public R logout(HttpSession session) {
        session.invalidate(); // 注销session，也会删除redis的session
        return R.ok();
    }

    @GetMapping("/getLoginUser")  //验证登入状态
    public R getLoginUser(HttpSession session) {
        UserEntity userEntity = (UserEntity) session.getAttribute(AuthCons.LOGIN_USER);
        if (userEntity != null) {
            // 已经登录了
            return R.ok().put("data", userEntity);
        } else {
            // 没有登录
            return R.ok();
        }
    }

    @PostMapping("/queryUser")  //修改密码验证用户
    public R queryUser(@RequestBody Map<String, Object> map) {
        log.debug("name----------:{}", map);

        if (map == null || map.isEmpty()) { //传入了一个空值
            throw new BusinessException("用户名不能为空", 500);
        }
        String name = map.get("name") + "";
        if (StringUtils.isEmpty(name)) { //传入的用户名是空的
            throw new BusinessException("用户名不能为空", 500);
        }

        //1.查询用户
        UserEntity userEntity = userService.queryUser(name);

        if (userEntity == null) {  // 查询用户是否存在
            throw new BusinessException("用户不存在", 500);
        }

        //2. 获取用户的邮箱
        String email = userEntity.getEmail();
        // 隐藏邮箱
        String hidenEmail = getHidenEmail(email);
        // 获取邮箱的登入地址
        String emailLongUrl = getEmailLongUrl(email);
        // 发送内容格式化
        String msg = "修改密码的连接已经发送到您【%s】的邮箱，请<a href='%s'>登录</a>邮箱查看";
        String formatMsg = String.format(msg, hidenEmail, emailLongUrl);

        //3. 发送邮件
        sendEmail(email, userEntity.getUsername());
        // 4.响应用户
        return R.ok().put("msg", formatMsg);
    }

    private void sendEmail(String e, String username) { //发送邮件
        Map<String, String> map = new HashMap<>();
        map.put("username", username);

        //生成token
        String token = JWTUtils.createToken(map, 1000 * 60 * 10); // 10m
        String url = "http://localhost/auth/changePassword.html?token=" + token;

        // 封装邮箱对象
        Email email = new Email();
        email.setTitle("2103商城用户密码修改");
        email.setContent("点击<a href ='" + url + "'>这里</a>修改密码,连接30分钟内有效，请尽快修改。");
        email.setReceiverList(e); //收件人，即为修改者的邮箱地址

        // 发送给MQ
        rabbitTemplate.convertAndSend(RabbitMQCons.SENDSMS_EXCHANGE, "email.send", email);
    }

    public String getEmailLongUrl(String email) {  //截取邮箱模式：QQ 163 等，获得邮箱发送地址
        String url = "http://www.mail.%s.com";
        String substring = email.substring(email.lastIndexOf("@") + 1, email.lastIndexOf("."));
        return String.format(url, substring);
    }

    public String getHidenEmail(String email) { //截取邮箱，第四位到@前，的数字改为*
        String subEmail = email.substring(4, email.lastIndexOf("@"));
        String replace = email.replace(subEmail, "*****");
        return replace;
    }

    @PostMapping("/changePassword")
    public R changePassword(@RequestBody Map<String,String> map){
        String password=map.get("password");
        String token=map.get("token");
        if (map==null||map.isEmpty()){
            return R.error(550,"参数为空");
        }
        if (StringUtils.isEmpty(token)||StringUtils.isEmpty(password)){
            return R.error(550,"验证为空");
        }
        //校验token
        DecodedJWT decodedJWT = JWTUtils.checkToken(token);
        if (decodedJWT==null){
            return R.error(550,"校验失败");
        }
        //从token中获取信息
        String username = JWTUtils.getData(decodedJWT, "username");
        UserEntity user = userService.findUser("username", username);
        if (user==null){
            return R.error(550,"用户不存在");
        }
        //修改的密码加密
        user.setPassword(BCrypt.hashpw(password,BCrypt.gensalt()));
        //修改密码
        userService.updateById(user);
        return R.ok();
    }


}
